#include "monad.hpp"

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 需求：在只读环境 `Env`、可变状态 `int` 下写日志 `std::string`
struct Env
{
    double factor;
};

using MyStack = WriterT<std::string, ReaderT<Env, State<int, int>>>;

// 使用 lift 函数提升 ask 和 get
auto computation = MyStack::lift(MyStack::lift(ReaderT<Env, State<int, int>>::ask())) >>= [](Env e)
{
    return MyStack::lift(State<int, int>::get()) >>= [e](int s)
    {
        int n = static_cast<int>(s * e.factor);
        return MyStack::tell("factor applied\n") >> MyStack::lift(State<int, int>::put(n)) >> mreturn(n);
    };
};

// 运行复合 Monad
int main()
{
    Env env{2.0};
    int initial_state = 5;
    auto result = runWriter(computation.runWriterT >>=
                            [&](auto&& pair)
                            {
                                auto [a, log] = pair;
                                std::cout << "Result: " << a << "\nLog:\n" << log << std::endl;
                                return mreturn(a);
                            });

    return 0;
}